package log

import (
	"fmt"
	"gitlab.wwgame.com/wwgame/kratos/v2/log"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"strconv"
	"strings"
)

var _ log.Logger = (*ZapLogger)(nil)

var (
	_logPath       string = "./log"
	_logFileName          = "server.log"
	_logMaxSize    int    = 10
	_logMaxAge     int    = 30
	_logMaxBackups int    = 30
)

func init() {
	str := os.Getenv("LOG_FILE_NAME")
	if str != "" {
		_logFileName = str
	}

	str = os.Getenv("LOG_DIR")
	if str != "" {
		_logPath = str
	}
	_logPath = strings.TrimRight(_logPath, "/") + "/" + _logFileName

	str = os.Getenv("LOG_MAX_SIZE")
	maxSize, _ := strconv.Atoi(str)
	if maxSize > 0 {
		_logMaxSize = maxSize
	}

	str = os.Getenv("LOG_MAX_AGE")
	maxAge, _ := strconv.Atoi(str)
	if maxAge > 0 {
		_logMaxAge = maxAge
	}

	str = os.Getenv("LOG_MAX_BACK_UP")
	maxBackUp, _ := strconv.Atoi(str)
	if maxAge > 0 {
		_logMaxBackups = maxBackUp
	}
}

type ZapLogger struct {
	log  *zap.Logger
	Sync func() error
}

// Logger 配置zap日志,将zap日志库引入
func Logger() log.Logger {
	//配置zap日志库的编码器
	encoder := zapcore.EncoderConfig{
		TimeKey:    "time",
		LevelKey:   "level",
		NameKey:    "logger",
		CallerKey:  "caller",
		MessageKey: "msg",
		//StacktraceKey:  "stack",
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalColorLevelEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	return NewZapLogger(
		encoder,
		zap.NewAtomicLevelAt(zapcore.DebugLevel),
		//zap.AddStacktrace(zap.NewAtomicLevelAt(zapcore.ErrorLevel)),
		zap.AddCaller(),
		zap.AddCallerSkip(2),
		zap.Development(),
	)
}

// 日志自动切割，采用 lumberjack 实现的
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   _logPath,       //指定日志存储位置
		MaxSize:    _logMaxSize,    //日志的最大大小（M）
		MaxBackups: _logMaxBackups, //日志的最大保存数量
		MaxAge:     _logMaxAge,     //日志文件存储最大天数
		Compress:   false,          //是否执行压缩
	}
	return zapcore.AddSync(lumberJackLogger)
}

// NewZapLogger return a zap logger.
func NewZapLogger(encoder zapcore.EncoderConfig, level zap.AtomicLevel, opts ...zap.Option) *ZapLogger {
	//日志切割
	writeSyncer := getLogWriter()
	//设置日志级别
	level.SetLevel(zap.InfoLevel)
	var core zapcore.Core
	//开发模式下打印到标准输出
	// --根据配置文件判断输出到控制台还是日志文件--
	if strings.ToLower(os.Getenv("RUN_MODE")) == "dev" {
		core = zapcore.NewCore(
			zapcore.NewConsoleEncoder(encoder),                      // 编码器配置
			zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), // 打印到控制台
			level, // 日志级别
		)
	} else {
		core = zapcore.NewCore(
			zapcore.NewConsoleEncoder(encoder),                                                    // 编码器配置
			zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(writeSyncer)), // 打印到控制台和文件
			level, // 日志级别
		)
	}
	zapLogger := zap.New(core, opts...)
	return &ZapLogger{log: zapLogger, Sync: zapLogger.Sync}
}

// Log 实现log接口
func (l *ZapLogger) Log(level log.Level, keyvals ...interface{}) error {
	if len(keyvals) == 0 || len(keyvals)%2 != 0 {
		l.log.Warn(fmt.Sprint("Keyvalues must appear in pairs: ", keyvals))
		return nil
	}

	var data []zap.Field
	var msg string
	for i := 0; i < len(keyvals); i += 2 {
		if fmt.Sprint(keyvals[i]) == "msg" {
			msg = fmt.Sprint(keyvals[i+1])
			continue
		}
		data = append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i+1]))
	}

	switch level {
	case log.LevelDebug:
		l.log.Debug(msg, data...)
	case log.LevelInfo:
		l.log.Info(msg, data...)
	case log.LevelWarn:
		l.log.Warn(msg, data...)
	case log.LevelError:
		l.log.Error(msg, data...)
	case log.LevelFatal:
		l.log.Fatal(msg, data...)
	}
	return nil
}
